/* Copyright ©, 2022, ECARX (Hubei) Technology Co., Ltd. All rights reserved.
 *
 * NOTICE: This file contains information which is confidential and proprietary to ECARX
 * (Hubei) Technology Co., Ltd. and/or other developers. No license to any intellectual
 * property rights contained within this file is either granted or implied except as may be
 * provided in an agreement with ECARX (Hubei) Technology Co., Ltd.
 *
 * Any unauthorized copying or distribution of content from this file in whole or in part
 * is prohibited.
 */

#define LOG_NDEBUG 0
#define LOG_TAG "VendorVHalImpl"

#include "VendorVehicleServer.h"

#include <android-base/properties.h>
#include <utils/Looper.h>
#include <utils/SystemClock.h>

#include <ctime>
#include <string>
#include <unordered_set>
#include <vector>

#include "Dispatcher.h"
#include "PropValueStore.h"
#include "SafeQueue.h"
#include "vhal_core/property/PropertyStore.h"

//运行模式(aosp|debug)
const std::string runModeKey = "persist.vendor.ecarx.vhal.propconfig.runmode";

constexpr const int32_t NOT_AVAILABLE_PROPERTIES =
    0xFFFF | VehiclePropertyGroup::VENDOR | VehiclePropertyType::INT64_VEC | VehicleArea::GLOBAL;

namespace ecarx::vhal::core::notconfig {
std::map<int64_t, bool> notAvailables;
}
//存储所有实现的PropertyValue
ecarx::vhal::core::property::storage::PropValueStore mStorage;
namespace ecarx::vhal::core::impl {

// loop
namespace looper {
android::sp<android::Looper> mHandler = new android::Looper(false);
}

static utils::ConcurrentQueue<QueueTask<int32_t>> mSignalQueue(true);
static utils::BatchingConsumer<QueueTask<int32_t>> mBatchSignalConsumer;

static utils::ConcurrentQueue<QueueTask<VehiclePropValue>> mTaskQueue(true);
static utils::BatchingConsumer<QueueTask<VehiclePropValue>> mBatchTaskConsumer;

static property::storage::PropValueConsumer mPropertyValueReportConsumer;

VendorVehicleServer::VendorVehicleServer() : mRunMode(RunMode::AOSP) {
    auto mode = android::base::GetProperty(runModeKey, "aosp");
    VHALOG.d("persist.vendor.ecarx.vhal.propconfig.runmode is %s", mode.c_str());
    if (mode != "aosp") {
        mRunMode = RunMode::DEBUG;
    }
    //初始化特殊Property
    interface::ConfigDeclaration config = {
        .config = VehiclePropConfig{.prop = NOT_AVAILABLE_PROPERTIES,
                                    .access = VehiclePropertyAccess::READ,
                                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
        .initialValue = {.int64Values = {}}};

    configs.emplace_back(config);
    notAvailableProperty.prop = NOT_AVAILABLE_PROPERTIES;
    notAvailableProperty.areaId = 0;
    notAvailableProperty.status = VehiclePropertyStatus::AVAILABLE;
    notAvailableProperty.timestamp = 0;

    mBatchTaskConsumer.run(&mTaskQueue, std::bind(&VendorVehicleServer::onSetFunctionTask, this,
                                                  std::placeholders::_1));
}

VendorVehicleServer::~VendorVehicleServer() {
    mBatchSignalConsumer.requestStop();
    mSignalQueue.deactivate();
    mBatchSignalConsumer.waitStopped();

    mBatchTaskConsumer.requestStop();
    mTaskQueue.deactivate();
    mBatchTaskConsumer.waitStopped();

    mPropertyValueReportConsumer.requestStop();
    mStorage.deactivate();
    mPropertyValueReportConsumer.waitStopped();

    delete mDID;
}

void VendorVehicleServer::onSetFunctionTask(const QueueTask<VehiclePropValue>& data) {
    if (data.action == Action::SET) {
        const VehiclePropValue value = data.data[0];
        auto iter = propertyMap.find(value.prop);
        if (iter != propertyMap.end()) {
            mStorage.beginTransaction();
            iter->second->setFunctionValue(value);
            mStorage.endTransaction();
        } else {
            VHALOG.w("not found setable function by property 0x%x areaid %d.", value.prop,
                  value.areaId);
        }
    }
}

void VendorVehicleServer::onSignalReceiver(const QueueTask<int32_t>& data) {
    if (data.action == Action::SIGNAL_RECEIVE) {
        mStorage.beginTransaction();
        clock_t start = std::clock();
        const std::vector<int32_t>& changed = data.data;
        Dispatcher dispatcher(changed);
        for (auto signal : changed) {
            auto iter = signalToAreas.find(signal);
            if (iter != signalToAreas.end()) {
                for (auto* areaPtr : iter->second) {
                    dispatcher.dispatchSignal(this, areaPtr, signal, data.flag);
                }
            }
        }
        clock_t end = std::clock();
        VHALOG.d("Signal changed %zu processing time %fms", changed.size(),
              double(end - start) * 1000 / CLOCKS_PER_SEC);
        mStorage.endTransaction();
        if (mRunMode == RunMode::DEBUG) {
            //更新notconfig
            std::vector<int64_t> data;
            data.reserve(notconfig::notAvailables.size());
            for (auto key : notconfig::notAvailables) {
                data.emplace_back(key.first);
            }
            notAvailableProperty.value.int64Values = android::hardware::hidl_vec<int64_t>(data);
            notAvailableProperty.timestamp = android::elapsedRealtime();
            _mCallback(notAvailableProperty);
        }

    } else if (data.action == Action::PROFILE_RESTORE) {
        VHALOG.d("begin receiver Action::PROFILE_RESTORE");
        mStorage.beginTransaction();
        for (auto area : mRestoreAreas) {
            if (area->isSupportProfile() || area->isSupportRefrence()) {
                area->tryRecoveryTask(true);
            }
        }
        mStorage.endTransaction();
        VHALOG.d("end receiver Action::PROFILE_RESTORE");
    } else if (data.action == Action::INIT_RESTORE) {
        VHALOG.d("begin receiver Action::INIT_RESTORE");
        mStorage.beginTransaction();
        for (auto area : mRestoreAreas) {
            area->tryRecoveryTask(true);
        }
        mStorage.endTransaction();
        VHALOG.d("end receiver Action::INIT_RESTORE");
        mTaskQueue.endInit();
    }
}

bool VendorVehicleServer::addProperty(property::IProperty* property) {
    if (property->getPropertyId() == 0){
        for (auto kv : property->getAreas()) {
            auto area = kv.second;
            //添加关心属性的处理函数
            for (auto& propsKV : area->getCareProps()) {
                auto iter =
                    propChangeCallbacks.try_emplace(propsKV.first, std::vector{propsKV.second});
                if (!iter.second) {
                    iter.first->second.emplace_back(propsKV.second);
                }
            }
            //添加关心信号的Area
            for (const auto signalId : kv.second->getOwnSignals()) {
                auto iter = signalToAreas.try_emplace(signalId, std::vector<property::Area*>{area});
                if (!iter.second) {
                    iter.first->second.emplace_back(kv.second);
                }
            }       
        }
        property->setWorkPhase(WorkPhase::READY_PHASE);
        return true;
    } 
    //排除无效的Property,即Property的状态是notavailable,
    //处于debug模式状态下忽略属性自身的状态,即所有属性功能都是配置的
    else if (mRunMode == RunMode::DEBUG || !property->invalidProperty()) {
        interface::ConfigDeclaration declaration;
        std::vector<VehicleAreaConfig> areaConfigs;
        areaConfigs.reserve(property->getAreas().size());
        propertyMap.try_emplace(property->getPropertyId(), property);
        auto& config = property->getConfig();
        for (auto kv : property->getAreas()) {
            auto area = kv.second;
            //添加AreaConfig
            areaConfigs.emplace_back(area->getAreaConfig());
            //添加需要Profile/DID恢复的Area
            if (area->isSupportProfile() || area->isSupportDID()) {
                mRestoreAreas.emplace_back(kv.second);
            }
            //添加关心属性的处理函数
            for (auto& propsKV : area->getCareProps()) {
                auto iter =
                    propChangeCallbacks.try_emplace(propsKV.first, std::vector{propsKV.second});
                if (!iter.second) {
                    iter.first->second.emplace_back(propsKV.second);
                }
            }
            //添加关心信号的Area
            for (const auto signalId : kv.second->getOwnSignals()) {
                auto iter = signalToAreas.try_emplace(signalId, std::vector<property::Area*>{area});
                if (!iter.second) {
                    iter.first->second.emplace_back(kv.second);
                }
            }
            //获取初始值
            auto& value = area->getValue();
            if (config.changeMode != VehiclePropertyChangeMode::STATIC ||
                value.status == VehiclePropertyStatus::AVAILABLE) {
                declaration.initialAreaValues.try_emplace(area->getAreaId(), value.value);
            }
        }

        config.areaConfigs = areaConfigs;
        declaration.config = config;
        configs.emplace_back(declaration);
        property->setWorkPhase(WorkPhase::READY_PHASE);
        return true;
    } else {
        return false;
    }
}

const property::IProperty* VendorVehicleServer::getProperty(int32_t propertyId) const {
    auto iter = propertyMap.find(propertyId);
    if (iter != propertyMap.end()) {
        return iter->second;
    }
    return nullptr;
}

void VendorVehicleServer::onSetProperty(const VehiclePropValue& value) {
    mTaskQueue.push(QueueTask<VehiclePropValue>{.action = Action::SET, .data = {value}});
}

bool VendorVehicleServer::isSupported(int32_t propId){
    auto iter = propertyMap.find(propId);
    return iter!=propertyMap.end();
}

void VendorVehicleServer::onSignalChanged(const std::vector<int32_t>& changed) {
    mSignalQueue.push(QueueTask<int32_t>{.action = Action::SIGNAL_RECEIVE, .data = changed, .flag = android::elapsedRealtimeNano()});
}

void VendorVehicleServer::setTransfers(
    const std::vector<std::shared_ptr<ecarx::transfer::ITransfer>>& transfers) {
    for (auto transfer : transfers) {
        this->mTransfers.emplace_back(transfer);
        transfer->registerStateHandler(
            std::bind(&VendorVehicleServer::onTransferReady, this, std::placeholders::_1));
        transfer->onSignalChanged(
            std::bind(&VendorVehicleServer::onSignalChanged, this, std::placeholders::_1));
    }
}

void VendorVehicleServer::setPlatformProfile(persist::PlatformProfile* platformProfile) {
    mPlatformProfile = platformProfile;
    if (mPlatformProfile != nullptr) {
        mPlatformProfile->addProfileListener(this);
    }
}

void VendorVehicleServer::setDID(persist::DID* did) {
    mDID = did;
}

void VendorVehicleServer::onSwitchProfile(persist::Profile* lastProfile,
                                          persist::Profile* currentProfile) {
    if (lastProfile != nullptr) {
        VHALOG.d("onSwitchProfile laste profile %d current profile %d", lastProfile->getProfileId(),
              currentProfile->getProfileId());
        // 保存最后使用的偏好
        if (lastProfile->getCurrentPreference() != nullptr) {
            lastProfile->getCurrentPreference()->save();
        }
        lastProfile->save();
        mSignalQueue.push(QueueTask<int32_t>{.action = Action::PROFILE_RESTORE});
    } else {
        VHALOG.d("onSwitchProfile last profile null current profile %d",
              currentProfile->getProfileId());
    }
}



void VendorVehicleServer::openTransfers(std::function<void()>&& transferReadyCb) {
    mTransferReadyCallback = transferReadyCb;

    //E371SOL-8142 service config is reset when libipcp inited by multi threads.
    /*
    std::vector<std::thread> threadList;
    for (auto& transfer : mTransfers) {
        threadList.push_back(std::thread([&transfer]() { transfer->open(); }));
    }
    for_each(threadList.begin(), threadList.end(), mem_fn(&std::thread::detach));
    */
    for (auto& transfer : mTransfers) {
        transfer->open();
    }
}

void VendorVehicleServer::onTransferReady(ecarx::transfer::NetState state) {
    static bool allReady = false;
    if (state == ecarx::transfer::NetState::Ready) {
        if (allReady) {
            VHALOG.d("has init all props");
            return;
        }
        bool ready;
        for (auto& transfer : mTransfers) {
            ready = transfer->getState() == ecarx::transfer::NetState::Ready;
            if (!ready) {
                break;
            }
        }
        if (ready) {
            allReady = true;
            if (mTransferReadyCallback) {
                mTransferReadyCallback();
            }
        }
    } else if (state == ecarx::transfer::NetState::Ready && allReady) {
        VHALOG.d("has init all props");
    }
}

RunMode VendorVehicleServer::getRunMode() {
    return mRunMode;
}

void VendorVehicleServer::setRunMode(RunMode mode) {
    VHALOG.d("set vhal run mode is %s", mode == RunMode::AOSP ? "aosp" : "debug");
    mRunMode = mode;
}

void VendorVehicleServer::initAllProperties() {
    clock_t start = std::clock();
    //初始化Profile,这一步可以确定创建了哪一个Profile
    if (mPlatformProfile != nullptr) {
        mPlatformProfile->onInit();
    }
    auto& propStore = property::getPropertyStore();
    mStorage.beginTransaction();
    for (auto it=propStore.begin();it!=propStore.end();) {
        auto property = it->get()->toIProperty();
        property->setDID(mDID);
        property->setPlatformProfile(mPlatformProfile);
        it->get()->init(this);
        it->get()->onInit();
        if(!addProperty(property)){
            it=propStore.erase(it);
        }else{
            it++;
        }
    }
    mStorage.endTransaction();
    clock_t end = std::clock();
    VHALOG.d("init all Properties %zu time %fms", propStore.size(),
          double(end - start) * 1000 / CLOCKS_PER_SEC);
    //初始化需要主动发起一次恢复任务
    mSignalQueue.push(QueueTask<int32_t>{.action = Action::INIT_RESTORE});
    mSignalQueue.endInit();
}

std::vector<interface::ConfigDeclaration> VendorVehicleServer::onGetAllPropertyConfig() const {
    return configs;
};

void VendorVehicleServer::registerUpdateCallback(const HalServerCommit&& callback) {
    _mCallback = callback;
    mPropertyValueReportConsumer.run(&mStorage, callback);
    mBatchSignalConsumer.run(&mSignalQueue, std::bind(&VendorVehicleServer::onSignalReceiver, this,
                                                      std::placeholders::_1));
}

std::unique_ptr<VehiclePropValue> VendorVehicleServer::getPropValue(int32_t propertyId,
                                                                    int32_t areaId) {
    return mStorage.readValueOrNull(propertyId, areaId);
};
bool VendorVehicleServer::setPropValue(const VehiclePropValue& value) {
    auto iter = propertyMap.find(value.prop);
    if (iter != propertyMap.end()) {
        mStorage.beginTransaction();
        bool res = iter->second->setFunctionValue(value);
        mStorage.endTransaction();
        return res;
    } else {
        VHALOG.d("not found setable function by property 0x%x areaid %d.", value.prop, value.areaId);
        return false;
    }
}

void VendorVehicleServer::onPropertyValue(const VehiclePropValue& value,CommitMode mode) {
    if (mStorage.writeValue(value,mode)) {
        //属性发生变化需要通知关心该属性的业务
        RecordId recId = {.prop = value.prop, .area = value.areaId};
        auto iter = propChangeCallbacks.find(recId);
        if (iter != propChangeCallbacks.end()) {
            for (auto& _callback : iter->second) {
                _callback(value);
            }
        }
    }
}

property::Area* VendorVehicleServer::findArea(int32_t propertyId, int32_t areaId) {
    auto iter = propertyMap.find(propertyId);
    if (iter != propertyMap.end()) {
        return iter->second->getArea(areaId);
    }
    return nullptr;
}

bool VendorVehicleServer::dump(
    [[maybe_unused]] const int fd,
    const android::hardware::hidl_vec<android::hardware::hidl_string>& options) {
    return true;
}

static void runLoop() {
    android::Looper::setForThread(looper::mHandler);
    VHALOG.d("run loop start.");
    while (!looper::mHandler->isPolling()) {
        looper::mHandler->pollOnce(-1);
    }
    VHALOG.d("run loop end.");
}
static std::thread mHandlerThread(runLoop);

}  // namespace ecarx::vhal::core::impl
